#include <sys/resource.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <aura.h>
#include <auraplus.h>
#include "private.h"
#include <aura_wchar.h>



extern pid_t s_processId;

AURA_API_(Aura_ProcessId) AuraProcess_GetCurrentId()
{
    return s_processId;
}

AURA_API_(Aura_Void) AuraProcess_Exit(
        /* [in] */ Aura_ExitCode exitCode)
{
    _exit((int)exitCode);
}

AURA_API AuraProcess_GetStartInfo(
        /* [out] */ Aura_PWChar pwImageName,
        /* [out] */ Aura_PWChar pwArguments)
{
    pid_t pid = getpid();
    int fd = 0;
    char szProcFile[128];
    char szCmdLine[AURA_MAX_PATH] = {0};
    char *p;
    char *pArgStart;
    int res = 0;
    memset(szCmdLine, 0, AURA_MAX_PATH);
    sprintf(szProcFile, "/proc/%d/cmdline", pid);
    fd = open(szProcFile, O_RDONLY);
    if (-1 == fd) {
        Aura_printf(" failed to open proc file.");
        return AURA_E_FAIL;
    }
    res = read(fd, szCmdLine, AURA_MAX_PATH);
    if (res < 0) {
        Aura_printf(" failed to read .");
        return AURA_E_FAIL;
    }
    close(fd);
    p = strstr(szCmdLine, "loader");
    if(NULL != p){
        p = szCmdLine+strlen(szCmdLine)+1;
    } else {
        //Cut the linux run command: ".\"
        p = szCmdLine + 2;
    }
    AnsiToUnic(pwImageName, p);
    pwArguments[0] = 0;
    p = p + strlen(p) + 1;
    pArgStart = p;
    if(0 != *pArgStart){
        char *pCmdEnd = szCmdLine + AURA_MAX_PATH;
        //Change '\0' to space
        while(pCmdEnd > (p+1)){
            if((*p =='\0') && (*(p + 1) == '\0')){
                break;
            }
            if(*p =='\0'){
                *p = ' ';
            }
            p++;
        }
//        printf("pArgStart:%s.\n", pArgStart);
        p = strstr(pArgStart, "DBG_FLAG");
        if(NULL != p){
            *p = '\0';
        }

        AnsiToUnic(pwArguments, pArgStart);
    }

    return AURA_NOERROR;
}

AURA_API AuraProcess_GetPriorityRank(//current
        /* [out] */ Aura_ThreadPriorityRank * pPriorityRank)
{
    FixMe("Not implemented yet.");
    return AURA_E_NOT_IMPLEMENTED;
}

AURA_API AuraProcess_SetPriorityRank(
        /* [out] */ Aura_ThreadPriorityRank priorityRank)
{
    FixMe("Not implemented yet.");
    return AURA_E_NOT_IMPLEMENTED;
}

AURA_API AuraProcess_GetProcessorTimes(
        /* [out] */ Aura_Millisecond32 * pUserTime,
        /* [out] */ Aura_Millisecond32 * pPrivilegedTime)
{
    struct rusage usage;
    int res = 0;

    assert((NULL != pUserTime) || (NULL != pPrivilegedTime));

    res = getrusage(RUSAGE_SELF, &usage);
    if (res < 0) {
        goto E_FAIL_EXIT;
    }
    if (NULL != pUserTime) {
        *pUserTime = usage.ru_utime.tv_sec * 1000 \
                   + usage.ru_utime.tv_usec/1000;
    }
    if (NULL != pPrivilegedTime) {
        *pPrivilegedTime = usage.ru_stime.tv_sec*1000 \
                         + usage.ru_stime.tv_usec/1000;
    }
    return AURA_NOERROR;

E_FAIL_EXIT:
    return GetLastAuraECode();
}

AURA_API AuraProcess_GetMemoryInformation(
        /* [out] */ Aura_Int32 * pPrivateVirtualMemorySize,
        /* [out] */ Aura_Int32 * pSharedVirtualMemorySize,
        /* [out] */ Aura_Int32 * pPrivatePhysicalMemorySize,
        /* [out] */ Aura_Int32 * pSharedPhysicalMemorySize)
{
    char szProcStatm[AURA_MAX_PATH];
    char szStatm[AURA_MAX_PATH] = {0};
    Aura_ECode ec = AURA_NOERROR;
    int iReadSize;
    int fdStatm;
    int iPhysicalPages = 0;
    int iPhysicalResident = 0;
    int iPhysicalShare = 0;
    int iPhysicalTrs = 0;
    int iPhysicalLrs = 0;
    int iPhysicalDrs = 0;
    int iPhysicalDt = 0;


    sprintf(szProcStatm, "/proc/%d/statm", s_processId);
    fdStatm = open(szProcStatm, O_RDONLY);
    if(-1 == fdStatm){
        goto E_FAIL_EXIT;
    }
    iReadSize = read(fdStatm, szStatm, AURA_MAX_PATH);
    if(-1 == iReadSize){
        goto E_FAIL_EXIT;
    }

    sscanf(szStatm, "%d %d %d %d %d %d %d\n",
        &iPhysicalPages,
        &iPhysicalResident,
        &iPhysicalShare,
        &iPhysicalTrs,
        &iPhysicalLrs,
        &iPhysicalDrs,
        &iPhysicalDt);

    if(NULL != pPrivateVirtualMemorySize){
        *pPrivateVirtualMemorySize
            = (iPhysicalPages - iPhysicalShare) * _PAGE_SIZE;
    }
    if(NULL != pSharedVirtualMemorySize){
        *pSharedVirtualMemorySize = iPhysicalShare * _PAGE_SIZE;
    }
    if(NULL != pPrivatePhysicalMemorySize){
        *pPrivatePhysicalMemorySize
            = (iPhysicalPages - iPhysicalShare) * _PAGE_SIZE;
    }
    if(NULL != pSharedPhysicalMemorySize){
        *pSharedPhysicalMemorySize = iPhysicalShare * _PAGE_SIZE;
    }

    close(fdStatm);

    return AURA_NOERROR;

E_FAIL_EXIT:
    ec = GetLastAuraECode();
    if (fdStatm > 0) {
        close(fdStatm);
    }
    return ec;
}
